home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / POV-Ray 3.0.2 / src / MacSource / UndoRedoSystem.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-03-04  |  15.4 KB  |  587 lines  |  [TEXT/CWIE]

  1. /*
  2.     This file contains functions that support undo and redo actions
  3.     for a single text editor (window).
  4.  
  5.  
  6.     This file is for POV-Ray 3.0.1 for MacOS!
  7.     The POV-Ray-Team is allowed to use this source code as they like
  8.     to use it.
  9.  
  10.     Created by Thorsten Froehlich, 1997.
  11. */
  12.  
  13. /*
  14.     This file will ONLY work with the TE32K text editor!
  15.     ====================================================
  16.  
  17.     This is a standard C undo/redo system. If you use C++ and
  18.     a text editor class,  these variables and functions should
  19.     be members of the class. Then each text editor (window)
  20.     will have its own undo/redo. (My original version is C++.)
  21.     With this standard C source code you can only support ONE
  22.     text editor (window) without modifications.
  23.  
  24.     Use gUndoBufferCount and gRedoBufferCount to enable/disable the
  25.     "Undo" and "Redo" menu items, e.g. if the counter is > 0 enable
  26.     the menu item, if it is == 0 disable it.
  27.  
  28.     How it works:
  29.     -------------
  30.     Place the Begin_Make_Undoable and End_Make_Undoable around your
  31.     code that changes the text (e.g. Cut,Paste...).
  32.     To make sure it works you have to set the selection range as it
  33.     is required. E.g. if you perform a Cut operation make sure the
  34.     text that is cut out is selected BEFORE you call
  35.     Begin_Make_Undoable and after the text is cut out make sure
  36.     there is no (an empty) selection BEFORE you call
  37.     End_Make_Undoable.
  38. */
  39.  
  40. #include <Types.h>
  41.  
  42. #include "TE32K.h"
  43.  
  44. #include "UndoRedoSystem.h"
  45.  
  46. /* Use this if you write a C++ class */
  47. /*
  48.     TE32KHandle gTextedit;
  49. */
  50.  
  51.  
  52. /* This is to be compatible with POV-Ray 3.0.1 for MacOS */
  53.  
  54. #include "TextEditor.h"
  55. #define gTextedit gSrcWind_TE32KH
  56.  
  57.  
  58. /* Variables and structures for the undo system */
  59.  
  60. My_UndoBuffer_Typedef gUndoBuffer[kMaxUndoRedo];
  61. long gUndoRedoSelStart;
  62. long gUndoRedoSelEnd;
  63. long gUndoRedoTextLength;
  64. int gUndoBufferCount;
  65. Boolean gUndoMaking;
  66. Boolean gNoMonitoring;
  67.  
  68. /* Variables and structures for the redo system */
  69.  
  70. My_RedoBuffer_Typedef gRedoBuffer[kMaxUndoRedo];
  71. int gRedoBufferCount;
  72. Boolean gRedoMaking;
  73.  
  74.  
  75. /*
  76.     Use Init_UndoRedoSystem and Dispose_UndoRedoSystem in open and close
  77.     text editor (window) function.
  78. */
  79.  
  80. void Init_UndoRedoSystem(void)
  81. {
  82.     int i;
  83.  
  84.     gUndoBufferCount = 0;
  85.     gRedoBufferCount = 0;
  86.     gUndoMaking = false;
  87.     gRedoMaking = false;
  88.     gNoMonitoring = false;
  89.  
  90.     for(i = 0; i < kMaxUndoRedo; i++)
  91.     {
  92.         gUndoBuffer[i].text = NULL;
  93.         gRedoBuffer[i].text = NULL;
  94.     }
  95. }
  96.  
  97. void Dispose_UndoRedoSystem(void)
  98. {
  99.     Clear_UndoBuffer();
  100.     Clear_RedoBuffer();
  101. }
  102.  
  103. /*
  104.     Use Check_CanUndo and Check_CanRedo to enable / disable your menu items.
  105.     Use Get_UndoCommand and Get_RedoCommand to get the command names for the menu items.
  106. */
  107.  
  108. Boolean Check_CanUndo(void)
  109. {
  110.     if((gUndoBufferCount > 0) || (gUndoMaking == true))
  111.         return true;
  112.     return false;
  113. }
  114.  
  115. Boolean Check_CanRedo(void)
  116. {
  117.     if((gRedoBufferCount > 0) || (gRedoMaking == true))
  118.         return true;
  119.     return false;
  120. }
  121.  
  122. void Get_UndoCommand(char *str)
  123. {
  124.     *str = 0;
  125.     if(gUndoBufferCount > 0)
  126.         BlockMove(gUndoBuffer[gUndoBufferCount - 1].command, str, 20);
  127. }
  128.  
  129. void Get_RedoCommand(char *str)
  130. {
  131.     *str = 0;
  132.     if(gRedoBufferCount > 0)
  133.         BlockMove(gRedoBuffer[gRedoBufferCount - 1].command, str, 20);
  134. }
  135.  
  136. /*
  137.     Use Begin_UndoRedo_Monitoring and End_UndoRedo_Monitoring for undo correction
  138.     if the executed operation changes text but is NOT undoable (e.g. "Replace All")
  139.     In case of "Replace All" remember to call this for every single "Replace"
  140.     because some monitored text may be between two replaced text parts.
  141. */
  142.  
  143. void Begin_UndoRedo_Monitoring(void)
  144. {
  145.     End_Make_Undoable();
  146.     End_Make_Redoable();
  147.  
  148.     gUndoRedoSelStart = (*gTextedit)->selStart;
  149.     gUndoRedoSelEnd = (*gTextedit)->selEnd;
  150.  
  151.     gUndoRedoTextLength = (*gTextedit)->teLength;
  152. }
  153.  
  154. void End_UndoRedo_Monitoring(Boolean change_undo,Boolean change_redo)
  155. {
  156.     long lendif;
  157.     int i;
  158.  
  159.     if(gNoMonitoring == true)
  160.         return;
  161.  
  162.     lendif = (*gTextedit)->teLength - gUndoRedoTextLength;
  163.  
  164.     if(lendif != 0)
  165.     {
  166.         if(change_undo == true)
  167.         {
  168.             for(i = 0; i < gUndoBufferCount; i++)
  169.             {
  170.                 if(gUndoBuffer[i].selStart >= gUndoRedoSelStart)
  171.                     gUndoBuffer[i].selStart += lendif;
  172.                 if(gUndoBuffer[i].selEnd >= gUndoRedoSelEnd)
  173.                     gUndoBuffer[i].selEnd += lendif;
  174.                 if(gUndoBuffer[i].selStart < 0)
  175.                     gUndoBuffer[i].selStart = 0;
  176.                 if(gUndoBuffer[i].selEnd < 0)
  177.                     gUndoBuffer[i].selEnd = 0;
  178.                 if(gUndoBuffer[i].selStart > (*gTextedit)->teLength)
  179.                     gUndoBuffer[i].selStart = (*gTextedit)->teLength;
  180.                 if(gUndoBuffer[i].selEnd > (*gTextedit)->teLength)
  181.                     gUndoBuffer[i].selEnd = (*gTextedit)->teLength;
  182.             }
  183.         }
  184.         if(change_redo == true)
  185.         {
  186.             for(i = 0; i < gRedoBufferCount; i++)
  187.             {
  188.                 if(gRedoBuffer[i].selStart >= gUndoRedoSelStart)
  189.                     gRedoBuffer[i].selStart+=lendif;
  190.                 if(gRedoBuffer[i].selEnd >= gUndoRedoSelEnd)
  191.                     gRedoBuffer[i].selEnd += lendif;
  192.                 if(gRedoBuffer[i].selStart < 0)
  193.                     gRedoBuffer[i].selStart = 0;
  194.                 if(gRedoBuffer[i].selEnd < 0)
  195.                     gRedoBuffer[i].selEnd = 0;
  196.                 if(gRedoBuffer[i].selStart > (*gTextedit)->teLength)
  197.                     gRedoBuffer[i].selStart = (*gTextedit)->teLength;
  198.                 if(gRedoBuffer[i].selEnd > (*gTextedit)->teLength)
  199.                     gRedoBuffer[i].selEnd = (*gTextedit)->teLength;
  200.             }
  201.         }
  202.     }
  203. }
  204.  
  205.  
  206. /*
  207.     Use Begin_Make_Undoable and End_Make_Undoable to make a operation's changes undoable.
  208.  
  209.     NOTE: If the undo buffer is full the last item will be removed automatically.
  210.     Called by My_DoRedo to allow undo for the redo operation.
  211.  
  212.     Parameters:
  213.     cammand   -   pass a string that can be displayed in addition to the undo menu item.
  214.  
  215.     They will return:
  216.     false if undo is impossible (e.g. out of memory).
  217.     true if undo is possible.
  218. */
  219.  
  220. Boolean Begin_Make_Undoable(char *command,Boolean merge)
  221. {
  222.     Handle fulltext;
  223.     long len,oldlen,addlen;
  224.  
  225.     if(gUndoMaking == true)
  226.         End_Make_Undoable();
  227.  
  228.     Begin_UndoRedo_Monitoring();
  229.  
  230.     gUndoBuffer[gUndoBufferCount - 1].mergeable = merge;
  231.  
  232.     if((merge == true) && (gUndoBufferCount > 0))
  233.     {
  234.         if((strcmp(command,gUndoBuffer[gUndoBufferCount - 1].command) == 0) && (gUndoBuffer[gUndoBufferCount - 1].mergeable == true))
  235.         {
  236.             if((*gTextedit)->selEnd == gUndoBuffer[gUndoBufferCount - 1].selStart)
  237.             {
  238.                 gUndoBufferCount--;
  239.                 oldlen = GetHandleSize(gUndoBuffer[gUndoBufferCount].text);
  240.                 addlen = (*gTextedit)->selEnd - (*gTextedit)->selStart;
  241.                 len = oldlen + addlen;
  242.                 SetHandleSize(gUndoBuffer[gUndoBufferCount].text, len);
  243.                 if(GetHandleSize(gUndoBuffer[gUndoBufferCount].text) != len)
  244.                 {
  245.                     gUndoBufferCount++;
  246.                     return false;
  247.                 }
  248.                 fulltext = TE32KGetText(gTextedit);
  249.                 if(fulltext == NULL)
  250.                 {
  251.                     gUndoBufferCount++;
  252.                     return false;
  253.                 }
  254.                 HLock(fulltext);
  255.                 HLock(gUndoBuffer[gUndoBufferCount].text);
  256.                 BlockMove(*(gUndoBuffer[gUndoBufferCount].text), *(gUndoBuffer[gUndoBufferCount].text) + addlen, oldlen);
  257.                 BlockMove((*fulltext) + (*gTextedit)->selStart, *(gUndoBuffer[gUndoBufferCount].text), addlen);
  258.                 HUnlock(gUndoBuffer[gUndoBufferCount].text);
  259.                 HUnlock(fulltext);
  260.                 gUndoBuffer[gUndoBufferCount].selStart = (*gTextedit)->selStart;
  261.             }
  262.             else if((*gTextedit)->selStart == gUndoBuffer[gUndoBufferCount - 1].selEnd)
  263.             {
  264.                 gUndoBufferCount--;
  265.                 oldlen = GetHandleSize(gUndoBuffer[gUndoBufferCount].text);
  266.                 addlen = (*gTextedit)->selEnd - (*gTextedit)->selStart;
  267.                 len = oldlen + addlen;
  268.                 SetHandleSize(gUndoBuffer[gUndoBufferCount].text, len);
  269.                 if(GetHandleSize(gUndoBuffer[gUndoBufferCount].text) != len)
  270.                 {
  271.                     gUndoBufferCount++;
  272.                     return false;
  273.                 }
  274.                 fulltext = TE32KGetText(gTextedit);
  275.                 if(fulltext == NULL)
  276.                 {
  277.                     gUndoBufferCount++;
  278.                     return false;
  279.                 }
  280.                 HLock(fulltext);
  281.                 HLock(gUndoBuffer[gUndoBufferCount].text);
  282.                 BlockMove((*fulltext) + (*gTextedit)->selStart, *(gUndoBuffer[gUndoBufferCount].text) + oldlen, addlen);
  283.                 HUnlock(gUndoBuffer[gUndoBufferCount].text);
  284.                 HUnlock(fulltext);
  285.                 gUndoBuffer[gUndoBufferCount].selStart = (*gTextedit)->selStart;
  286.             }
  287.             else
  288.             {
  289.                 gUndoBuffer[gUndoBufferCount - 1].mergeable = false;
  290.                 merge = false;
  291.             }
  292.         }
  293.         else
  294.         {
  295.             gUndoBuffer[gUndoBufferCount - 1].mergeable = false;
  296.             merge = false;
  297.         }
  298.     }
  299.     else
  300.     {
  301.         if(gUndoBufferCount > 0)
  302.             gUndoBuffer[gUndoBufferCount - 1].mergeable = false;
  303.         merge = false;
  304.     }
  305.  
  306.     if(merge == false)
  307.     {
  308.         if(gUndoBufferCount == kMaxUndoRedo)
  309.         {
  310.             if(gUndoBuffer[0].text != NULL)
  311.                 DisposeHandle(gUndoBuffer[0].text);
  312.             BlockMove(&gUndoBuffer[1], &gUndoBuffer[0], sizeof(My_UndoBuffer_Typedef) * (kMaxUndoRedo - 1));
  313.             gUndoBufferCount--;
  314.         }
  315.  
  316.         len = (*gTextedit)->selEnd - (*gTextedit)->selStart;
  317.         gUndoBuffer[gUndoBufferCount].text = NewHandle(len);
  318.         if(gUndoBuffer[gUndoBufferCount].text == NULL)
  319.             return false;
  320.  
  321.         fulltext = TE32KGetText(gTextedit);
  322.         if(fulltext == NULL)
  323.             return false;
  324.         HLock(fulltext);
  325.         HLock(gUndoBuffer[gUndoBufferCount].text);
  326.         BlockMove((*fulltext) + (*gTextedit)->selStart, *(gUndoBuffer[gUndoBufferCount].text), len);
  327.         HUnlock(gUndoBuffer[gUndoBufferCount].text);
  328.         HUnlock(fulltext);
  329.  
  330.         gUndoBuffer[gUndoBufferCount].selStart = (*gTextedit)->selStart;
  331.         BlockMove(command, &(gUndoBuffer[gUndoBufferCount].command), 20);
  332.     }
  333.  
  334.     gUndoMaking = true;
  335.  
  336.     return true;
  337. }
  338.  
  339. Boolean End_Make_Undoable(void)
  340. {
  341.     if(gUndoMaking == false)
  342.         return true;
  343.     gUndoMaking = false;
  344.  
  345.     if(gUndoBuffer[gUndoBufferCount].text == NULL)
  346.         return false;
  347.  
  348.     gUndoBuffer[gUndoBufferCount].selEnd = (*gTextedit)->selEnd;
  349.  
  350. //    printf("UNDO Buffered (%d): %d - %d\n",gUndoBufferCount,gUndoBuffer[gUndoBufferCount].selStart,gUndoBuffer[gUndoBufferCount].selEnd);
  351.  
  352.     End_UndoRedo_Monitoring(false,true);
  353.  
  354.     gUndoBufferCount++;
  355.  
  356.     return true;
  357. }
  358.  
  359.  
  360. /*
  361.     Use Begin_Make_Redoable and End_Make_Redoable to make an undone operation redoable.
  362.  
  363.     NOTE: If the redo buffer is full the last item will be removed automatically.
  364.     Usually called by My_DoUndo only.
  365.  
  366.     Parameters:
  367.     cammand   -   pass a string that can be displayed in addition to the undo menu item.
  368.  
  369.     They will return:
  370.     false if redo is impossible (e.g. out of memory).
  371.     true if redo is possible.
  372. */
  373.  
  374. Boolean Begin_Make_Redoable(char *command,Boolean merge)
  375. {
  376.     Handle fulltext;
  377.     long len;
  378.  
  379.     if(gRedoMaking == true)
  380.         End_Make_Redoable();
  381.  
  382.     Begin_UndoRedo_Monitoring();
  383.  
  384.     if(gRedoBufferCount == kMaxUndoRedo)
  385.     {
  386.         if(gRedoBuffer[0].text != NULL)
  387.             DisposeHandle(gRedoBuffer[0].text);
  388.         BlockMove(&gRedoBuffer[1], &gRedoBuffer[0], sizeof(My_RedoBuffer_Typedef) * (kMaxUndoRedo - 1));
  389.         gRedoBufferCount--;
  390.     }
  391.  
  392.     len = (*gTextedit)->selEnd - (*gTextedit)->selStart;
  393.     gRedoBuffer[gRedoBufferCount].text = NewHandle(len);
  394.     if(gRedoBuffer[gRedoBufferCount].text == NULL)
  395.         return false;
  396.  
  397.     fulltext = TE32KGetText(gTextedit);
  398.     if(fulltext == NULL)
  399.         return false;
  400.     HLock(fulltext);
  401.     HLock(gRedoBuffer[gRedoBufferCount].text);
  402.     BlockMove((*fulltext) + (*gTextedit)->selStart, *(gRedoBuffer[gRedoBufferCount].text), len);
  403.     HUnlock(gRedoBuffer[gRedoBufferCount].text);
  404.     HUnlock(fulltext);
  405.  
  406.     gRedoBuffer[gRedoBufferCount].selStart = (*gTextedit)->selStart;
  407.     BlockMove(command, &(gRedoBuffer[gRedoBufferCount].command), 20);
  408.  
  409.     gRedoMaking = true;
  410.  
  411.     return true;
  412. }
  413.  
  414. Boolean End_Make_Redoable(void)
  415. {
  416.     if(gRedoMaking == false)
  417.         return true;
  418.  
  419.     gRedoMaking = false;
  420.  
  421.     if(gRedoBuffer[gRedoBufferCount].text == NULL)
  422.         return false;
  423.  
  424.     gRedoBuffer[gRedoBufferCount].selEnd = (*gTextedit)->selEnd;
  425.  
  426. //    printf("REDO Buffered (%d): %d - %d\n",gRedoBufferCount,gRedoBuffer[gRedoBufferCount].selStart,gRedoBuffer[gRedoBufferCount].selEnd);
  427.  
  428.     End_UndoRedo_Monitoring(true,false);
  429.  
  430.     gRedoBufferCount++;
  431.  
  432.     return true;
  433. }
  434.  
  435.  
  436. /*
  437.     Use ClearUndoBuffer and ClearRedoBuffer to delete the undo/redo buffers.
  438.     You have to call them at the end of your program and may have to call them
  439.     if you perform not undoable or not redoable operations.
  440. */
  441.  
  442. void Clear_UndoBuffer(void)
  443. {
  444.     int i;
  445.  
  446.     if(gUndoMaking == true)
  447.         End_Make_Undoable();
  448.  
  449.     for(i = 0; i < gUndoBufferCount; i++)
  450.     {
  451.         if(gUndoBuffer[i].text != NULL)
  452.             DisposeHandle(gUndoBuffer[i].text);
  453.         gUndoBuffer[i].text = NULL;
  454.     }
  455.  
  456.     gUndoBufferCount = 0;
  457. }
  458.  
  459. void Clear_RedoBuffer(void)
  460. {
  461.     int i;
  462.  
  463.     if(gRedoMaking == true)
  464.         End_Make_Redoable();
  465.  
  466.     for(i =0; i < gRedoBufferCount; i++)
  467.     {
  468.         if(gRedoBuffer[i].text != NULL)
  469.             DisposeHandle(gRedoBuffer[i].text);
  470.         gRedoBuffer[i].text = NULL;
  471.     }
  472.  
  473.     gRedoBufferCount = 0;
  474. }
  475.  
  476.  
  477. /*
  478.     My_DoUndo and My_DoRedo provide the undo / redo operations.
  479. */
  480.  
  481. Boolean My_DoUndo(void)
  482. {
  483.     if(gUndoMaking == true)
  484.         End_Make_Undoable();
  485.  
  486.     if(gUndoBufferCount > 0)
  487.     {
  488.         // These five lines protect the memory because Monitoring may result in Starts & Ends that are out of range (still investigating cause, March 4th)
  489.         if((gUndoBuffer[gUndoBufferCount - 1].selStart < 0) || (gUndoBuffer[gUndoBufferCount - 1].selEnd > (*gTextedit)->teLength))
  490.         {
  491.             Clear_UndoBuffer();
  492.             return false;
  493.         }
  494.  
  495.         gUndoBufferCount--;
  496.  
  497.         printf("UNDO %s (%d):  Current: %d - %d  Undone %d - %d\n",
  498.                 gUndoBuffer[gUndoBufferCount].command,
  499.                 gUndoBufferCount,
  500.                 gUndoBuffer[gUndoBufferCount].selStart,
  501.                 gUndoBuffer[gUndoBufferCount].selEnd,
  502.                 gUndoBuffer[gUndoBufferCount].selStart,
  503.                 gUndoBuffer[gUndoBufferCount].selStart +
  504.                 GetHandleSize(gUndoBuffer[gUndoBufferCount].text));
  505.  
  506.         if(gUndoBuffer[gUndoBufferCount].text == NULL)
  507.             return false;
  508.  
  509.         TE32KSetSelect(gUndoBuffer[gUndoBufferCount].selStart,gUndoBuffer[gUndoBufferCount].selEnd,gTextedit);
  510.  
  511.         gNoMonitoring = true;
  512.         Begin_Make_Redoable(gUndoBuffer[gUndoBufferCount].command,false);
  513.  
  514.         TE32KDelete(gTextedit);
  515.         TE32KSetSelect(gUndoBuffer[gUndoBufferCount].selStart,
  516.                     gUndoBuffer[gUndoBufferCount].selStart,gTextedit);
  517.  
  518.         HLock(gUndoBuffer[gUndoBufferCount].text);
  519.         TE32KInsert(*(gUndoBuffer[gUndoBufferCount].text),GetHandleSize(gUndoBuffer[gUndoBufferCount].text),gTextedit);
  520.         HUnlock(gUndoBuffer[gUndoBufferCount].text);
  521.  
  522.         End_Make_Redoable();
  523.         gNoMonitoring = false;
  524.         TE32KSetSelect(gUndoBuffer[gUndoBufferCount].selStart,gUndoBuffer[gUndoBufferCount].selStart+GetHandleSize(gUndoBuffer[gUndoBufferCount].text),gTextedit);
  525.  
  526.         DisposeHandle(gUndoBuffer[gUndoBufferCount].text);
  527.         gUndoBuffer[gUndoBufferCount].text = NULL;
  528.  
  529.         return true;
  530.     }
  531.  
  532.     return false;
  533. }
  534.  
  535. Boolean My_DoRedo(void)
  536. {
  537.     if(gRedoMaking == true)
  538.         End_Make_Redoable();
  539.  
  540.     if(gRedoBufferCount > 0)
  541.     {
  542.         // These five lines protect the memory because Monitoring may result in Starts & Ends that are out of range (still investigating cause, March 4th)
  543.         if((gRedoBuffer[gRedoBufferCount - 1].selStart < 0) || (gRedoBuffer[gRedoBufferCount - 1].selEnd > (*gTextedit)->teLength))
  544.         {
  545.             Clear_RedoBuffer();
  546.             return false;
  547.         }
  548.  
  549.         gRedoBufferCount--;
  550.  
  551.         printf("REDO %s (%d):  Current: %d - %d  Redone %d - %d\n",
  552.                 gRedoBuffer[gRedoBufferCount].command,
  553.                 gRedoBufferCount,
  554.                 gRedoBuffer[gRedoBufferCount].selStart,
  555.                 gRedoBuffer[gRedoBufferCount].selEnd,
  556.                 gRedoBuffer[gRedoBufferCount].selStart,
  557.                 gRedoBuffer[gRedoBufferCount].selStart +
  558.                 GetHandleSize(gRedoBuffer[gRedoBufferCount].text));
  559.  
  560.         if(gRedoBuffer[gRedoBufferCount].text == NULL)
  561.             return false;
  562.  
  563.         TE32KSetSelect(gRedoBuffer[gRedoBufferCount].selStart,gRedoBuffer[gRedoBufferCount].selEnd,gTextedit);
  564.  
  565.         gNoMonitoring = true;
  566.         Begin_Make_Undoable(gRedoBuffer[gRedoBufferCount].command,false);
  567.  
  568.         TE32KDelete(gTextedit);
  569.         TE32KSetSelect(gRedoBuffer[gRedoBufferCount].selStart,gRedoBuffer[gRedoBufferCount].selStart,gTextedit);
  570.  
  571.         HLock(gRedoBuffer[gRedoBufferCount].text);
  572.         TE32KInsert(*(gRedoBuffer[gRedoBufferCount].text),GetHandleSize(gRedoBuffer[gRedoBufferCount].text),gTextedit);
  573.         HUnlock(gRedoBuffer[gRedoBufferCount].text);
  574.  
  575.         End_Make_Undoable();
  576.         gNoMonitoring = false;
  577.         TE32KSetSelect(gRedoBuffer[gRedoBufferCount].selStart,gRedoBuffer[gRedoBufferCount].selStart+GetHandleSize(gRedoBuffer[gRedoBufferCount].text),gTextedit);
  578.  
  579.         DisposeHandle(gRedoBuffer[gRedoBufferCount].text);
  580.         gRedoBuffer[gRedoBufferCount].text = NULL;
  581.  
  582.         return true;
  583.     }
  584.  
  585.     return false;
  586. }
  587.